import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, Put, Query, Req } from '@nestjs/common';
import { BaseController } from '../base/base.controller';
import { DbService } from '@app/db';
import { Device } from '@app/db/entities/Device';
import { In } from 'typeorm';
import { AddBatchDto, AddDto, UpdateDto, PageDto } from './dto';
import { DtoPipe } from '../pipes/dto/dto.pipe';
import { DeviceService } from './device.service';
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';

@Controller('device')
export class DeviceController extends BaseController{
    constructor(
        private readonly service:DeviceService,
        private readonly db:DbService,

    ){
        super()
    }

    //获取拥有的设备的
    @Get('owned/device')
    async ownedDevice(@Req() { belong, member }) {
        const owners:number[] = []
        if(belong != 0) {
            owners.push(member.tenantId)
        }

        const query = this.db.device.createQueryBuilder()
        query.select(['Device.id', 'Device.type'])
        
        if(owners.length != 0) {
            owners.forEach(owner => {
                query.andWhere(`JSON_CONTAINS(owners, '${owner}')`)
            })
        }

        let result:any = {
            device : [],
            //portModel : []
        }

        result.device = await query.getMany()

        if(result.device.length > 0) {
            // const portModels:number[] = []
            // result.device.forEach(d => {
            //     if(!portModels.includes(d.portModel)) {
            //         portModels.push(d.portModel)
            //     }
            // })

            // result.portModel = await this.db.portModel.find({id : In(portModels)}, ['id', 'ports'])
        }


        return this.successRes(result)
    }

    @Post('page')
    async page(@Body() dto:PageDto, @Req() { belong, member }) {

        const result = belong == 0 ? (await this.service.page(dto)) : (await this.service.pageOfTentant(dto, member))

        return this.successRes(result)

    }

    @Post('add')
    async add(@Body(new DtoPipe({skipMissingProperties : false})) dto:AddDto) {
        const data:QueryDeepPartialEntity<Device> = {
            chargeType : dto.chargeType,
            aliProduct : dto.aliProduct,
            portCount : dto.portCount,
            createTime : this.utils.time(),
        }

        

        if(dto.name) {
            data.name = dto.name
        }

        if(dto.owner) {
            data.owners = [dto.owner]
        }
        

        // if(dto.simId) {
        //     data.simId = dto.simId
        // }

        if(dto.remark) {
            data.remark = dto.remark
        }

        const res = await this.db.device.insert(data)
        if(res && res.affectedRows > 0) {
            if(dto.registerAli) {
                const deviceId = res.rows[0].id
                const r = await this.service.registerToAli(dto.aliProduct, deviceId)
                if(r) {
                    if(r.success) {
                        await this.db.device.update({id : deviceId}, {atAli : 1, aliSecret : r.data.deviceSecret})
                    }else if(r.code == 'iot.device.AlreadyExistedDeviceName') {
                        const r1 = await this.service.queryDeviceInfo(dto.aliProduct, deviceId)
                        if(r1.success && r1.data) {
                            await this.db.device.update({id : deviceId}, {atAli : 1, aliSecret : r1.data.deviceSecret})
                        }
                    }
                    
                }
            }
            return this.successRes()
        }

        return this.failRes()
    }


    @Post('add/batch')
    async addBatch(@Body(new DtoPipe({skipMissingProperties : false})) dto:AddBatchDto, @Req() { locale }) {
        const data:KeyToValueType<Device>[] = []
        let owners = dto.owner ? [dto.owner] : null

        let simCardNos:string[] = []
        dto.rows.forEach(row => {
            if(row.simCard && simCardNos.includes(row.simCard) == false) {
                simCardNos.push(row.simCard)
            }
        })


        
        let simNoToIds = new Map()
        // if(simCardNos.length > 0) {
        //     let simCards = await this.db.iotSim.find({cardNo : In(simCardNos)}, ['id', 'cardNo'])
        //     simCardNos = null
        //     simCards.forEach(card => {
        //         simNoToIds.set(card.cardNo, card.id)
        //     })
        //     simCards = null
        // }
        

        const time = this.utils.time()


        

        dto.rows.forEach(row => {
            let item:KeyToValueType<Device> = {
                chargeType : dto.chargeType,
                aliProduct : dto.aliProduct,
                //simId : 0,
                owners : null,
                createTime : time
            }

            // if(row.simCard) {
            //     let simId = simNoToIds.get(row.simCard)
            //     if(simId != undefined) {
            //         item.simId = simId
            //     }
            // }

            item.name = row.name || ''

            if(owners) item.owners = owners

            data.push(item)

        })

        const res = await this.db.device.insert(data)
        if(res) {
            if(dto.registerAli && res.affectedRows > 0) {
                const ids = res.rows.map(row => row.id)
            }
        }


        return this.failRes()
    }

    @Put('update/:id')
    async update(@Body(new DtoPipe({skipNullProperties : true})) dto:UpdateDto, @Param('id', ParseIntPipe) id:number, @Req() { locale, member, belong }) {
        if(isNaN(id) || id < 1) return

        const ownerId = dto.owner
        delete dto.owner


        let fields = Object.keys(dto) as (keyof Device)[]
        if(fields.length == 0) return

        if(ownerId != undefined) {
            fields.push('owners')
        }

        const device = await this.db.device.findOne({id : id}, fields)
        if(!device) return

        let updateData:KeyToValueType<Device> = {}
        for(let k in device) {
            if(k in dto && device[k] != dto[k]) {
                updateData[k] = dto[k]
            }
        }


        if(ownerId != undefined) {
            if(belong == 0) { //平台
                if(ownerId == 0) { //接触所有的所有者
                    updateData.owners = null
                }else {
                    if(device.owners) {
                        if(device.owners[0] != ownerId) { //更改了
                            updateData.owners = [ownerId]
                        }
                    }else {
                        updateData.owners = [ownerId]
                    }
                    
                }
            }else {
                //找出自己当前的位置
                let i = device.owners.findIndex(owner => owner == member.tenantId) + 1
                if(device.owners[i] != ownerId) {
                    device.owners.splice(i)
                    device.owners.push(ownerId)
                    updateData.owners = device.owners
                }
            }
        }


        if(Object.keys(updateData).length == 0) return this.successRes()

        // if('portCount' in updateData) {
        //     if(updateData.portCount == 0) {
        //         updateData.ports = null
        //     }else {
        //         let offset = updateData.portCount - device.portCount
        //         updateData.ports = device.ports
        //         if(offset < 0) { //端口减少
        //             updateData.ports.splice(updateData.portCount)
                    
        //         }else { //端口增加
        //             for(let i = 0; i < offset; i ++) {
        //                 updateData.ports.push({
        //                     status : 0
        //                 })
        //             }
        //         }
        //     }
        // }

        updateData.updateTime = this.utils.time()

        const res = await this.db.device.update({id : id}, updateData)
        return res === 0 ? this.failRes() : this.successRes()
    }


    @Post('bind/station')
    async bindStation(@Body('ids') ids:number[], @Body('id') id:number, @Req() { member }) {
        const r = await this.db.device.update({id : ids.length == 1 ? ids[0] : In(ids)}, {stationId : id})
        return r > 0 ? this.successRes() : this.failRes()
    }

    @Post('unbind/station')
    async unbindStation(@Body('ids') ids:number[], @Req() { member }) {
        const r = await this.db.device.update({id : ids.length == 1 ? ids[0] : In(ids)}, {stationId : 0})
        return r > 0 ? this.successRes() : this.failRes()
    }

    @Post('batch/bind/tenant')
    async batcBindTenant(@Body('ids') ids:number[], @Body('owner') owner:number, @Req() { belong, member}) {
        
        let owners:number[] = null
        if(belong == 0) { //平台的
            owners = [owner]
        }else {
            const tenant = await this.db.tenant.findOne({id : member.tenantId}, {level : true})
            //查找一个设备出来
            const device = await this.db.device.findOne({id : ids[0]}, {owners : true})
            owners = device.owners
            owners.splice(tenant.level + 1)
            owners.push(owner)
        }

        
        const res = await this.db.device.update({id : In(ids)}, {owners : owners})
        return res === 0 ? this.failRes() : this.successRes()
        
    }


    @Post('batch/unbind/tenant')
    async batchUnbindTenant(@Body('ids') ids:number[], @Req() { belong, member}) {
        let owners:number[] = null
        if(belong != 0) { //平台的
            const tenant = await this.db.tenant.findOne({id : member.tenantId}, {level : true})
            const device = await this.db.device.findOne({id : ids[0]}, {owners : true})
            owners = device.owners
            owners.splice(tenant.level + 1)
        }

        const res = await this.db.device.update({id : In(ids)}, {owners : owners})
        return res === 0 ? this.failRes() : this.successRes()
        
    }


    @Get('port/:id')
    async port(@Param('id', ParseIntPipe) id:number) {
        console.log(id)
        const data = await this.db.device.findOne({id}, ['portData', 'portStatus'])
        return this.successRes(data)
    }

    
    @Get('queryProductList')
    async queryProductList(){
        const res = await this.service.queryProductList()
        return this.successRes(res)
    }

    @Delete('delete/:id')
    async delete(@Param('id', ParseIntPipe) id:number) {
        if(id <= 0) return
        const res = await this.db.device.delete({id : id})
        return res === 0 ? this.failRes() : this.successRes()
    }


    @Post('pushSetting')
    async pushSetting(@Body() deviceIds:number[]) {
        this.service.sendSettingToDevice(deviceIds)
        return this.successRes()
    }

}
